home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HyperLib 1997 Winter - Disc 1
/
HYPERLIB-1997-Winter-CD1.ISO.7z
/
HYPERLIB-1997-Winter-CD1.ISO
/
オンラインウェア
/
PRG
/
Z80ppc 160.sit
/
Z80ppc 160
/
Init_Z80.c
< prev
next >
Wrap
Text File
|
1995-11-19
|
11KB
|
360 lines
/* Z80 Emulator
Copyright (C) 1994 G.Woigk
This file is part of Mac Spectacle and it is free software
See application.c for details
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16.Jan.95 Fixed wrong calculation of parity flag KIO !
28.Jan.95 CMD_PROFILE KIO !
29.Mrz.95 Separated this file from Z80.c KIO !
01.Nov.95 Started work on paged memory model again KIO !
*/
#include "kio.h"
#include "z80.options"
#include "z80.h"
#include "application.h"
#include "quick_strings.h"
#include "z80 main.h"
#include "display.h"
#define maxrampages 8 // 128k RAM in 8 pages 16k
#define maxrompages 5 // the plus3 has 4 roms + if1 rom
#define pagesize 0x4000 // 16 kByte
#define pagemask 0x3FFF // 16k-1
#define pagebits 14 // 14 bit address inside page
int z80_hardware = zx_48k; // actually emulated hardware ( as set up by Init_Z80() )
#if CMD_PROFILE
Boolean count_instr = false;
long *cnt_xx = nil; // array: count use of normal instructions
long *cnt_cb = nil; // array: count use of CB instructions
long *cnt_ed = nil; // array: count use of ED instructions
long *cnt_xy = nil; // array: count use of ix and iy instructions
long *cnt_xycb = nil; // array: count use of ix/CB and iy/CB instructions
#endif
#if PC_PROFILE
Boolean count_pc = false;
long *cnt_pc = nil; // array: count instruction executions per location in RAM
#endif
// ----- The Z80 core --------------------------------------------------------------
Char** CORE_M = nil; // master handle for all allocated RAM and ROM
Char* CORE = nil; // do not use any longer!!!
Char* rpage[4]; // mapped in pages for reading
Char* wpage[4]; // mapped in pages for writing
Char* ram[maxrampages]; // real RAM pages
Char* rom[maxrompages]; // real ROM pages
Char* norom = nil; // dummy page for writing to ROM
Char zx128pagectrl = 0; // last byte sent to ZX 128's paging control port
// ----- The Z80 registers --------------------------------------------------
z80 zreg; // contains z80 registers on entry/return of Z80()
// ----- Flags after logic operations -------------------------------------
Char zlog_flags[256]; // convert: A -> Z80-flags with V=parity, S, Z, and C=0
#if !GENERATINGPOWERPC
Char mlog_flags[256]; // convert: A-register -> 68000 flags with V=parity and C=0
Char z80flags[256]; // convert: 68000 flagbyte -> Z80 flagbyte
Char m68flags[256]; // convert: Z80 flagbyte -> 68000 flagbyte
#endif
// ===== Utilities ========================================================
// ----- Peek, Poke and calculate EA for peeking and poking -----------------------------
// These are inappropriate for macros, because the address is used twice
// note: rpage[] and wpage[] pointers are calculated that way, that the unmasked address
// must be added to address the right byte in the Macintosh's RAM !
Char* RdPtr ( Short addr ) { return rpage[addr>>pagebits] + addr; } // ptr for reading
Char* WrPtr ( Short addr ) { return wpage[addr>>pagebits] + addr; } // ptr for writing
Char Peek ( Short addr ) { return rpage[addr>>pagebits][addr]; }
Poke ( Short addr, Char byte ) { wpage[addr>>pagebits][addr] = byte; }
// ----- Write from/to core, buffer and file -------------------------------------------
// file operations return 0 if ok else OS error
long tfu; // after read/write to file: bytes actually transferred
/* ----- Write buffer to file ----------------------------------------------------------
*/
OSErr Buffer2File ( void* bu, short fileID, long len )
{
tfu = len;
return FSWrite ( fileID, &tfu, bu );
}
/* ----- Read buffer from file --------------------------------------------------------
*/
OSErr File2Buffer ( short fileID, void* bu, long len )
{
tfu = len;
return FSRead ( fileID, &tfu, bu );
}
/* ----- Write core to file ------------------------------------------------------------
saves what the z80 cpu would read
*/
OSErr Core2File ( Short addr, short fileID, long len )
{ OSErr err; long n;
tfu = 0;
for ( err=noErr; !err && len; )
{ n = min ( len, pagesize-(addr&pagemask) );
PrintDebug ( CatString(CatString("¥pCore->File; addr: ",NumString(addr)), CatString("¥p; bytes: ",NumString(n))),0);
err = FSWrite ( fileID, &n, RdPtr(addr) );
addr += n;
len -= n;
tfu += n;
}
return err;
}
/* ----- Read core from file -----------------------------------------------------------
stores what the z80 cpu would write
ROM is automatically protected
*/
OSErr File2Core ( short fileID, Short addr, long len )
{ OSErr err; long n;
tfu = 0;
for ( err=noErr; !err && len; )
{ n = min ( len, pagesize-(addr&pagemask ) );
PrintDebug ( CatString(CatString("¥pFile->Core; addr: ",NumString(addr)), CatString("¥p; bytes: ",NumString(n))),0);
err = FSRead ( fileID, &n, WrPtr(addr) );
addr += n;
len -= n;
tfu += n;
}
return err;
}
/* ----- Copy core to buffer -----------------------------------------------------------
copies what the z80 cpu would read
*/
Core2Buffer ( Short addr, void* bu, long len )
{ long n;
while ( len )
{ n = min ( len, pagesize-(addr&pagemask ) );
memcpy ( bu, RdPtr(addr), n );
bu = (Char*)bu+n;
addr += n;
len -= n;
}
}
/* ----- Copy buffer to core ------------------------------------------------------------
copies what the z80 cpu would write
*/
Buffer2Core ( void* bu, Short addr, long len )
{ long n;
while ( len )
{ n = min ( len, pagesize-(addr&pagemask ) );
memcpy ( WrPtr(addr), bu, n );
bu = (Char*)bu+n;
addr += n;
len -= n;
}
}
/* ----- Copy core to core --------------------------------------------------------------
copies what the z80 cpu would copy
*/
Core2Core ( Short src, Short dest, long len )
{ long n;
while (len)
{ n = min ( min ( len, pagesize-(src&pagemask ) ), pagesize-(dest&pagemask ) );
memcpy ( WrPtr(dest), RdPtr(src), n );
src += n;
dest += n;
len -= n;
}
}
/* ----- Copy buffer to buffer (just for completeness) ------------------------------------
*/
Buffer2Buffer ( void* src, void* dest, long len )
{
memcpy ( dest, src, len );
}
/* ----- Send byte to ZX 128's paging control port ----------------------------------------
Bits 0-2: Ram for top 16k: 0 is the usual bank; 7 contains some scratchpads used by the 128k editor.
Bit 3: Screen select: 0 => Use the normal screen in bank 5; 1 => Use the shadow screen in bank 7.
Bit 4: ROM for lower 16k: 0 => 128k editor; 1 => 48k BASIC
Bit 5: Lock. If set, disables all further paging.
*/
ZX128PageCtrl ( Char n )
{
if (z80_hardware!=zx_128) return; // not a ZX 128
if (zx128pagectrl&0x20) return; // further paging disabled
zx128pagectrl = n;
rpage[0] = (n&0x10) ? rom[1] : rom[0]; // ROM select
video_page = (n&0x08) ? ram[7] : ram[5]; // video RAM select
rpage[3] = wpage[3] = ram[n&0x07]-0xc000; // upper RAM page select
}
/* ----- Initialialize the z80 engine --------------------------------------------
allocate rom, ram, and norom pages
initialize rom[], ram[] and norom
initialize rpage[] and wpage[] for reset
CORE points to reset core which is allocated in 4 consecutive pages!
init random generator for r register handling
calculate flag tables
initialize zreg
reset z80
On a 68k machine:
・ the core is aligned to a multiple of 0x00010000
・ some byte behind the last byte a preset with rst0 opcodes
・ high words of pointers in zreg struct are set to point to the core
*/
InitZ80 ( int hardware )
{ int i, roms, rams;
OSErr err=noErr;
Char *p;
switch (hardware)
{
case zx_48k: roms=1; rams=3; break;
case zx_128: roms=2; rams=8; break;
default: abort("¥pInitZ80():","¥pillegal model number: ",NumString(hardware));
}
z80_hardware = hardware;
// allocate dummy write page for ROMs
if (!norom) norom = (Char*)NewPtr(pagesize);
if (!norom) abort_oomem ( "¥pInitZ80()" );
// dispose of old core
if (CORE_M) DisposHandle((Handle)CORE_M);
CORE = nil; CORE_M = nil;
for (i=maxrompages;i--;) rom[i] = nil;
for (i=maxrampages;i--;) ram[i] = nil;
for (i=4;i--;) rpage[i] = wpage[i] = norom-i*pagesize; // fail safe pointers
/* allocate rom and ram pages:
zx_48k: CORE+0x0000 = rom[0] = rpage[0]
CORE+0x4000 = ram[1] = rpage[1]
CORE+0x8000 = ram[2] = rpage[2]
CORE+0xC000 = ram[3] = rpage[3]
zx_128: CORE+0x0000 = rom[0] = rpage[0]
CORE+0x4000 = ram[5] = rpage[1]
CORE+0x8000 = ram[2] = rpage[2]
CORE+0xC000 = ram[0] = rpage[3]
*/
#if !GENERATINGPOWERPC
// put rom[0] and ram[1...3] resp. ram[5/2/0] in a memory block aligned to a multiple of 0x10000
// additional ram and rom is located physically before pointer CORE !!!
CORE_M = (Char**)TempNewHandle ((roms+rams)*pagesize+0x10010,&err);
if (!CORE_M||err) abort_oomem ( "¥pInitZ80()" );
HLock((Handle)CORE_M);
CORE = *CORE_M+(roms+rams)*pagesize;
CORE -= (Short)CORE;
memset ( CORE+0x10000, 199, 0x10 ); // rst 0
ABC=ADE=AHL=AIX=AIY=APC=ASP=CORE; // setup high words of register pointers
#else
// simple allocation in PowerPC version
CORE_M = (Char**)TempNewHandle ((roms+rams)*pagesize,&err);
if (!CORE_M||err) abort_oomem ( "¥pInitZ80()" );
HLock((Handle)CORE_M);
CORE = *CORE_M + (roms+rams-4)*pagesize; // to mimic 68k version
#endif
// initialize rom[] and ram[]
switch (z80_hardware)
{
case zx_48k:
rom[0] = CORE;
ram[1] = CORE+0x4000;
ram[2] = CORE+0x8000;
ram[3] = CORE+0xc000;
break;
case zx_128:
rom[0] = CORE;
ram[5] = CORE+0x4000;
ram[2] = CORE+0x8000;
ram[0] = CORE+0xc000;
p=CORE;
rom[1] = p-=pagesize;
for (i=0;i<rams;i++) if (!ram[i]) ram[i] = p-=pagesize;
break;
}
// initialize rpage[], wpage[]
for (i=4;i--;) rpage[i] = wpage[i] = CORE;
wpage[0] = norom;
// init z80 registers:
zreg.ff2 = zreg.aa2 = zreg.ff = zreg.aa = 0; // clear high bytes of A/A2 and F/F2
BC=DE=HL=IX=IY=PC=SP=BC2=DE2=HL2=0; // clear registers
RA=RA2=RF=RF2=RR=RI=0;
IFF1 = IFF2 = disabled; // disable interrupts
IM = 1; // interrupt mode := 1
WUFF= 0; // clear irpt, nmi
EXIT = 0; // clear watchdog
IRPTCMD = 0xff; // byte read from bus in im0 or im2 mode
// build flag tables:
// Z80: %SZ-H-VNC --- H & N ignored
// m68: %---XSZVC --- X ignored
// the unused flags correspond as follows: z80{%--1H2-N-} == m68{%1H2N----} 11.12.94 KIO !
for (i=0; i<256; i++)
{
zlog_flags[i] = (i&0x80) + ((i==0)<<6) + ( ( (~i+(i>>1)+(i>>2)+(i>>3)+(i>>4)+(i>>5)+(i>>6)+(i>>7))&1 ) << 2 );
#if !GENERATINGPOWERPC
mlog_flags[i] = ((i>=128)<<3) + ((i==0)<<2) + ( ( (~i+(i>>1)+(i>>2)+(i>>3)+(i>>4)+(i>>5)+(i>>6)+(i>>7))&1 ) << 1 );
z80flags[i] = ((i<<4)&0xc0) + ((i<<1)&4) + (i&1) + ((i>>2)&0x38) + ((i>>3)&2);
m68flags[i] = ((i>>4)&0x0c) + ((i>>1)&2) + (i&1) + ((i<<2)&0xe0) + ((i<<3)&0x10);
#endif
};
// initialize random generator for r register
GetDateTime((unsigned long*)&qd.randSeed);
}